home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dmake / save / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-10  |  15.0 KB  |  838 lines

  1.  
  2. /*
  3.  *  PARSE.C
  4.  *
  5.  *  Parse the next token or tokens
  6.  */
  7.  
  8. #include "defs.h"
  9. #include <stdarg.h>
  10. #ifndef AMIGA
  11. #include <suplib/string.h>
  12. #endif
  13.  
  14. Prototype void InitParser(void);
  15. Prototype void ParseFile(char *);
  16. Prototype token_t ParseAssignment(char *, token_t);
  17. Prototype token_t ParseDependency(char *, token_t);
  18. Prototype token_t GetElement(void);
  19. Prototype token_t XGetElement(void);
  20. Prototype void      ParseVariable(List *, short);
  21. Prototype char     *ParseVariableBuf(List *, ubyte *, short);
  22. Prototype char     *ExpandVariable(ubyte *, List *);
  23. Prototype token_t GetToken(void);
  24. Prototype void expect(token_t, token_t);
  25. Prototype void error(short, const char *, ...);
  26.  
  27.  
  28. Prototype char SymBuf[256];
  29. Prototype long LineNo;
  30.  
  31. char SpecialChar[256];
  32. char SChars[] = { ":=()\n\\\" \t\r\014" };
  33. char SymBuf[256];
  34. char AltBuf[256];
  35. char AltBuf2[256];
  36. long LineNo = 1;
  37. char *FileName = "";
  38. FILE *Fi;
  39.  
  40. void
  41. InitParser()
  42. {
  43.     short i;
  44.     for (i = 0; SChars[i]; ++i)
  45.     SpecialChar[(ubyte)SChars[i]] = 1;
  46. }
  47.  
  48. /*
  49.  *  Parse lines as follows:
  50.  *
  51.  *  symbol = ...
  52.  *  symbol ... : symbol ...
  53.  *    (commands, begin with tab or space)
  54.  *    (blank line)
  55.  *
  56.  *
  57.  */
  58.  
  59. void
  60. ParseFile(fileName)
  61. char *fileName;
  62. {
  63.     FILE *fi;
  64.     token_t t;
  65.  
  66.     if ((fi = fopen(fileName, "r")) == NULL)
  67.     error(FATAL, "Unable to open %s", fileName);
  68.     FileName = strdup(fileName);
  69.     Fi = fi;
  70.  
  71.     for (t = GetElement(); t; ) {
  72.     switch(t) {
  73.     case TokNewLine:
  74.         t = GetElement();
  75.         break;
  76.     case TokSym:
  77.         strcpy(AltBuf2, SymBuf);
  78.  
  79.         /*
  80.          *    check for '=' -- assignment
  81.          */
  82.  
  83.         t = GetElement();
  84.         if (t == TokEq)
  85.         t = ParseAssignment(AltBuf2, t);
  86.         else
  87.         t = ParseDependency(AltBuf2, t);
  88.         break;
  89.     default:
  90.         error(FATAL, "Expected a symbol!");
  91.         break;
  92.     }
  93.     }
  94. }
  95.  
  96. /*
  97.  *  Parse an asignment.  Parsed as-is (late eval)
  98.  *
  99.  *  t contains TokEq, ignore
  100.  */
  101.  
  102. token_t
  103. ParseAssignment(char *varName, token_t t)
  104. {
  105.     Var *var = MakeVar(varName, '$');
  106.     long len;
  107.     short done;
  108.     short eol = 1;
  109.     List tmpList;
  110.  
  111.     NewList(&tmpList);
  112.  
  113. #ifdef NOTDEF
  114.     {
  115.     short c;
  116.     while ((c = fgetc(Fi)) == ' ' || c == '\t')
  117.         ;
  118.     if (c != EOF)
  119.         ungetc(c, Fi);
  120.     }
  121. #endif
  122.  
  123.     while (fgets(AltBuf, sizeof(AltBuf), Fi)) {
  124.     len = strlen(AltBuf);
  125.  
  126.     if (eol && AltBuf[0] == '#') {
  127.         ++LineNo;
  128.         continue;
  129.     }
  130.     if (len && AltBuf[len-1] == '\n') {
  131.         ++LineNo;
  132.         --len;
  133.         if (len && AltBuf[len-1] == '\\') {
  134.         --len;
  135.         done = 0;
  136.         } else {
  137.         done = 1;
  138.         }
  139.         eol = 1;
  140.     } else {
  141.         done = 0;
  142.         eol = 0;
  143.     }
  144.     AltBuf[len] = 0;
  145.     {
  146.         long i;
  147.  
  148.         for (i = 0; i < len && (AltBuf[i] == ' ' || AltBuf[i] == '\t'); ++i)
  149.         ;
  150.         for (     ; i < len; ++i)
  151.         PutCmdListChar(&tmpList, AltBuf[i]);
  152.     }
  153.     if (done > 0)
  154.         break;
  155.     }
  156.  
  157.     /*
  158.      *    Now, load temp list into buffer and expand into the variable
  159.      */
  160.  
  161.     {
  162.     char *buf = malloc(CmdListSize(&tmpList) + 1);
  163.     CopyCmdListBuf(&tmpList, buf);
  164.     ExpandVariable(buf, &tmpList);
  165.     AppendCmdList(&tmpList, &var->var_CmdList);
  166.     free(buf);
  167.     }
  168.     return(GetElement());
  169. }
  170.  
  171. /*
  172.  *  Parse a dependency
  173.  */
  174.  
  175. token_t
  176. ParseDependency(char *firstSym, token_t t)
  177. {
  178.     DepRef  *lhs;
  179.     DepRef  *rhs;
  180.     List    lhsList;
  181.     List    rhsList;
  182.     List    *cmdList = malloc(sizeof(List));
  183.     long    nlhs = 0;
  184.     long    nrhs = 0;
  185.     short   ncol = 0;
  186.  
  187.     NewList(cmdList);
  188.     NewList(&lhsList);
  189.     NewList(&rhsList);
  190.  
  191.     ++nlhs;
  192.     for (CreateDepRef(&lhsList, firstSym); t != TokColon; t = GetElement()) {
  193.     expect(t, TokSym);
  194.     CreateDepRef(&lhsList, SymBuf);
  195.     ++nlhs;
  196.     }
  197.     t = GetElement();
  198.     if (t == TokColon) {
  199.     ++ncol;
  200.     t = GetElement();
  201.     }
  202.  
  203.     while (t != TokNewLine) {
  204.     expect(t, TokSym);
  205.     CreateDepRef(&rhsList, SymBuf);
  206.     ++nrhs;
  207.     t = GetElement();
  208.     }
  209.  
  210.     /*
  211.      *    parse command list
  212.      */
  213.  
  214.     {
  215.     short c;
  216.     short blankLine = 1;
  217.     short ws = 0;        /*  white space skip    */
  218.  
  219.     while ((c = getc(Fi)) != EOF) {
  220.         if (c == '\n') {
  221.         ++LineNo;
  222.         if (blankLine)
  223.             break;
  224.         PutCmdListChar(cmdList, '\n');
  225.         blankLine = 1;
  226.         continue;
  227.         }
  228.  
  229.         switch(c) {
  230.         case ' ':
  231.         case '\t':
  232.         if (blankLine) {    /*    remove all but one ws after nl */
  233.             ws = 1;
  234.             continue;
  235.         }
  236.         PutCmdListChar(cmdList, c);
  237.         break;
  238.         case '\\':
  239.         if (ws) {
  240.             PutCmdListChar(cmdList, ' ');
  241.             ws = 0;
  242.         }
  243.         c = getc(Fi);
  244.         if (c == '\n') {
  245.             blankLine = 1;
  246.             ++LineNo;
  247.             continue;
  248.         }
  249.         PutCmdListChar(cmdList, '\\');
  250.         PutCmdListChar(cmdList, c);
  251.         break;
  252.         default:
  253.         if (ws) {
  254.             PutCmdListChar(cmdList, ' ');
  255.             ws = 0;
  256.         }
  257.         PutCmdListChar(cmdList, c);
  258.         break;
  259.         }
  260.         blankLine = 0;
  261.     }
  262.     }
  263.     dbprintf(("parse: %d : %d\n", nlhs, nrhs));
  264.  
  265.     /*
  266.      *    formats allowed:
  267.      *
  268.      *        X :: Y    each item depends on all items (X x Y dependancies)
  269.      *        1 : N    item depends on items
  270.      *        N : N    1:1 map item to item
  271.      *        N : 1    items depend on item
  272.      */
  273.  
  274.     if (ncol == 1) {
  275.     while (lhs = RemHead(&lhsList)) {
  276.         if (GetHead(&lhsList)) {
  277.         for (rhs = GetHead(&rhsList); rhs; rhs = GetSucc(&rhs->rn_Node))
  278.             IncorporateDependency(lhs, DupDepRef(rhs), cmdList);
  279.         } else {
  280.         while (rhs = RemHead(&rhsList))
  281.             IncorporateDependency(lhs, rhs, cmdList);
  282.         }
  283.         IncorporateDependency(lhs, NULL, cmdList);
  284.         free(lhs);
  285.     }
  286.     } else if (nlhs == 1) {
  287.     lhs = RemHead(&lhsList);
  288.     while (rhs = RemHead(&rhsList))
  289.         IncorporateDependency(lhs, rhs, cmdList);
  290.     IncorporateDependency(lhs, NULL, cmdList);
  291.     free(lhs);
  292.     } else if (nrhs == 1) {
  293.     rhs = RemHead(&rhsList);
  294.     while (lhs = RemHead(&lhsList)) {
  295.         IncorporateDependency(lhs, rhs, cmdList);
  296.         free(lhs);
  297.     }
  298.     } else if (nlhs == nrhs) {
  299.     while ((lhs = RemHead(&lhsList)) && (rhs = RemHead(&rhsList))) {
  300.         IncorporateDependency(lhs, rhs, cmdList);
  301.         free(lhs);
  302.     }
  303.     } else {
  304.     error(FATAL, "%d items on the left, %d on the right of colon!", nlhs, nrhs);
  305.     }
  306.     return(t);
  307. }
  308.  
  309. /*
  310.  *  GetElement()    - return a token after variable/replace parsing
  311.  */
  312.  
  313. #ifdef NOTDEF
  314. token_t
  315. GetElement(void)
  316. {
  317.     token_t t = XGetElement();
  318.     return(t);
  319. }
  320. #endif
  321.  
  322. token_t
  323. GetElement(void)
  324. {
  325.     static List CmdList = { (Node *)&CmdList.lh_Tail, NULL, (Node *)&CmdList.lh_Head };
  326.     token_t t;
  327.     short c;
  328.  
  329. top:
  330.     if (PopCmdListSym(&CmdList, SymBuf, sizeof(SymBuf)) == 0) {
  331.     return(TokSym);
  332.     }
  333.  
  334.     t = GetToken();
  335. swi:
  336.     switch(t) {
  337.     case TokDollar:
  338.     case TokPercent:
  339.     c = fgetc(Fi);
  340.     if (c == '(') {
  341.         ParseVariable(&CmdList, (t == TokPercent) ? '%' : '$');
  342.  
  343.         /*
  344.          *    XXX how to handle dependancies verses nominal string concat?
  345.          */
  346.  
  347.         while ((c = fgetc(Fi)) != ' ' && c != '\t' && c != '\n' && c != ':') {
  348.         if (c == EOF)
  349.             break;
  350.         if (c == '$') {
  351.             t = TokDollar;
  352.             goto swi;
  353.         }
  354.         if (c == '%') {
  355.             t = TokPercent;
  356.             goto swi;
  357.         }
  358.         PutCmdListChar(&CmdList, c);
  359.         }
  360.         if (c != EOF)
  361.         ungetc(c, Fi);
  362.         goto top;
  363.     }
  364.     ungetc(c, Fi);
  365.     default:
  366.     break;
  367.     }
  368.     return(t);
  369. }
  370.  
  371. /*
  372.  *  ParseVariable() - parse a variable reference, expanding it into a
  373.  *  command list.  Fi begins at the first character in the variable name
  374.  *
  375.  *  $(NAME)
  376.  *  $(NAME:"from":"to")
  377.  *
  378.  */
  379.  
  380. void
  381. ParseVariable(List *cmdList, short c0)
  382. {
  383.     short c;
  384.     short i = 0;
  385.     Var *var;
  386.  
  387.     /*
  388.      *    variable name
  389.      */
  390.  
  391.     while ((c = getc(Fi)) != EOF && !SpecialChar[c])
  392.     AltBuf[i++] = c;
  393.     AltBuf[i] = 0;
  394.  
  395.     var = FindVar(AltBuf, c0);
  396.     if (var == NULL)
  397.     error(FATAL, "Variable %s does not exist", AltBuf);
  398.  
  399.     dbprintf(("ParseVariable: (%c:%c) %s\n", c0, c, AltBuf));
  400.  
  401.     /*
  402.      *    now, handle modifiers
  403.      */
  404.  
  405.     if (c == ')') {
  406.     CopyCmdList(&var->var_CmdList, cmdList);
  407.     return;
  408.     }
  409.     if (c != ':')
  410.     error(FATAL, "Bad variable specification after name");
  411.  
  412.     /*
  413.      *    source operation
  414.      */
  415.  
  416.     c = fgetc(Fi);
  417.     if (c == '\"') {
  418.     ungetc(c, Fi);
  419.     expect(GetToken(), TokStr);
  420.     c = fgetc(Fi);
  421.     } else {
  422.     i = 0;
  423.     while (c != ')' && c != ':' && c != EOF) {
  424.         SymBuf[i++] = c;
  425.         c = fgetc(Fi);
  426.     }
  427.     SymBuf[i] = 0;
  428.     }
  429.  
  430.     strcpy(AltBuf, SymBuf);
  431.  
  432.     /*
  433.      *    destination operation
  434.      */
  435.  
  436.     if (c == ')') {
  437.     CopyCmdListConvert(&var->var_CmdList, cmdList, AltBuf, AltBuf);
  438.     return;
  439.     }
  440.  
  441.     if (c != ':')
  442.     error(FATAL, "Bad variable replacement spec: %c", c);
  443.  
  444.     c = fgetc(Fi);
  445.     if (c == '\"') {
  446.     ungetc(c, Fi);
  447.     expect(GetToken(), TokStr);
  448.     c = fgetc(Fi);
  449.     } else {
  450.     i = 0;
  451.     while (c != ')' && c != ':' && c != EOF) {
  452.         SymBuf[i++] = c;
  453.         c = fgetc(Fi);
  454.     }
  455.     SymBuf[i] = 0;
  456.     }
  457.  
  458.     if (c != ')')
  459.     error(FATAL, "Bad variable replacement spec: %c", c);
  460.  
  461.     CopyCmdListConvert(&var->var_CmdList, cmdList, AltBuf, SymBuf);
  462. }
  463.  
  464. /*
  465.  *  Since this is recursively called we have to save/restore oru temporary
  466.  *  bufferse (SymBuf & AltBuf).  the buf pointer may itself be pointing
  467.  *  into these but we are ok since it is guarenteed >= our copy destination
  468.  *  as we index through it.
  469.  */
  470.  
  471.  
  472. char *
  473. ParseVariableBuf(List *cmdList, ubyte *buf, short c0)
  474. {
  475.     short c;
  476.     short i = 0;
  477.     Var *var;
  478.     char *symBuf = AllocPathBuffer();
  479.     char *altBuf = AllocPathBuffer();
  480.  
  481.     dbprintf(("ParseVariableBuf: (%c) %s\n", c0, buf));
  482.     /*
  483.      *    variable name
  484.      */
  485.  
  486.     while ((c = *buf++) && !SpecialChar[c])
  487.     altBuf[i++] = c;
  488.     altBuf[i] = 0;
  489.  
  490.     var = FindVar(altBuf, c0);
  491.     if (var == NULL)
  492.     error(FATAL, "Variable %s does not exist", altBuf);
  493.  
  494.     /*
  495.      *    now, handle modifiers
  496.      */
  497.  
  498.     if (c == ')') {
  499.     CopyCmdList(&var->var_CmdList, cmdList);
  500.     FreePathBuffer(symBuf);
  501.     FreePathBuffer(altBuf);
  502.     return(buf);
  503.     }
  504.     if (c != ':')
  505.     error(FATAL, "Bad variable specification after name");
  506.  
  507.     /*
  508.      *    source operation
  509.      */
  510.  
  511.     c = *buf++;
  512.  
  513.     if (c == '\"') {
  514.     i = 0;
  515.     while ((c = *buf++) && c != '\"')
  516.         symBuf[i++] = c;
  517.     if (c == '\"')
  518.         c = *buf++;
  519.     } else {
  520.     i = 0;
  521.     while (c && c != ')' && c != ':') {
  522.         symBuf[i++] = c;
  523.         c = *buf++;
  524.     }
  525.     }
  526.  
  527.     symBuf[i] = 0;
  528.     strcpy(altBuf, symBuf);
  529.  
  530.     /*
  531.      *    destination operation
  532.      */
  533.  
  534.     if (c == ')') {
  535.     CopyCmdListConvert(&var->var_CmdList, cmdList, altBuf, symBuf);
  536.     FreePathBuffer(symBuf);
  537.     FreePathBuffer(altBuf);
  538.     return(buf);
  539.     }
  540.  
  541.     if (c != ':')
  542.     error(FATAL, "Bad variable replacement spec: %c", c);
  543.  
  544.     c = *buf++;
  545.  
  546.     if (c == '\"') {
  547.     i = 0;
  548.     while ((c = *buf++) && c != '\"')
  549.         symBuf[i++] = c;
  550.     if (c == '\"')
  551.         c = *buf++;
  552.     } else {
  553.     i = 0;
  554.     while (c && c != ')' && c != ':') {
  555.         symBuf[i++] = c;
  556.         c = *buf++;
  557.     }
  558.     }
  559.     symBuf[i] = 0;
  560.  
  561.     if (c != ')')
  562.     error(FATAL, "Bad variable replacement spec: %c", c);
  563.  
  564.     dbprintf(("CopyConvert to %s %s (%s) %08lx\n", altBuf, symBuf, var->var_Node.ln_Name, GetHead(&var->var_CmdList)));
  565.  
  566.     CopyCmdListConvert(&var->var_CmdList, cmdList, altBuf, symBuf);
  567.     FreePathBuffer(symBuf);
  568.     FreePathBuffer(altBuf);
  569.     return(buf);
  570. }
  571.  
  572. char *
  573. ExpandVariable(buf, list)
  574. ubyte *buf;
  575. List *list;
  576. {
  577.     short c;
  578.     short n = 0;
  579.     short tmpListValid;
  580.     short keepInList;
  581.     List tmpList;
  582.     static int Levels;
  583.  
  584.     if (++Levels == 20)
  585.     error(FATAL, "Too many levels of variable recursion");
  586.  
  587.     if (list) {
  588.     keepInList = 1;
  589.     tmpListValid = 1;
  590.     } else {
  591.     keepInList = 0;
  592.     tmpListValid = 0;
  593.     list = &tmpList;
  594.     NewList(list);
  595.     }
  596.  
  597.     while (c = buf[n]) {
  598.     if (c == '$' || c == '%') {
  599.         if (buf[n+1] == '(') {
  600.         if (tmpListValid == 0) {
  601.             int i;
  602.  
  603.             for (i = 0; i < n; ++i)
  604.             PutCmdListChar(list, buf[i]);
  605.             tmpListValid = 1;
  606.         }
  607.         n = (ubyte *)ParseVariableBuf(list, buf + n + 2, c) - buf;
  608.         } else if (buf[n+1] == c) {
  609.         if (tmpListValid)
  610.             PutCmdListChar(list, c);
  611.         n += 2;
  612.         } else {
  613.         if (tmpListValid)
  614.             PutCmdListChar(list, c);
  615.         ++n;
  616.         }
  617.     } else {
  618.         if (tmpListValid)
  619.         PutCmdListChar(list, c);
  620.         ++n;
  621.     }
  622.     }
  623.     if (keepInList == 0) {
  624.     if (tmpListValid) {
  625.         buf = malloc(CmdListSize(list) + 1);
  626.         CopyCmdListBuf(list, buf);
  627.     }
  628.     }
  629.     --Levels;
  630.     return(buf);
  631. }
  632.  
  633.  
  634. #ifdef NOTDEF
  635.  
  636.     short c;
  637.     short i;
  638.     Var *var;
  639.  
  640.     /*
  641.      *    variable name
  642.      */
  643.  
  644.     while (c = *buf++ && !SpecialChar[c])
  645.     AltBuf[i++] = c;
  646.  
  647.     AltBuf[i] = 0;
  648.  
  649.     var = FindVar(AltBuf, c0);
  650.     if (var == NULL)
  651.     error(FATAL, "Variable %s does not exist", AltBuf);
  652.  
  653.     /*
  654.      *    now, handle modifiers
  655.      */
  656.  
  657.     if (c == ')') {
  658.     CopyCmdList(&var->var_CmdList, cmdList);
  659.     return;
  660.     }
  661.     if (c != ':')
  662.     error(FATAL, "Bad variable specification after name");
  663.  
  664.     /*
  665.      *    source operation
  666.      */
  667.  
  668.     c = fgetc(Fi);
  669.     if (c == '\"') {
  670.     ungetc(c, Fi);
  671.     expect(GetToken(), TokStr);
  672.     c = fgetc(Fi);
  673.     } else {
  674.     i = 0;
  675.     while (c != ')' && c != ':' && c != EOF) {
  676.         SymBuf[i++] = c;
  677.         c = fgetc(Fi);
  678.     }
  679.     }
  680.     SymBuf[i] = 0;
  681.  
  682.     strcpy(AltBuf, SymBuf);
  683.  
  684.     /*
  685.      *    destination operation
  686.      */
  687.  
  688.     if (c == ')') {
  689.     CopyCmdListConvert(&var->var_CmdList, cmdList, AltBuf, SymBuf);
  690.     return;
  691.     }
  692.  
  693.     if (c != ':')
  694.     error(FATAL, "Bad variable replacement spec: %c", c);
  695.  
  696.  
  697.     c = fgetc(Fi);
  698.     if (c == '\"') {
  699.     ungetc(c, Fi);
  700.     expect(GetToken(), TokStr);
  701.     c = fgetc(Fi);
  702.     } else {
  703.     i = 0;
  704.     while (c != ')' && c != ':' && c != EOF) {
  705.         SymBuf[i++] = c;
  706.         c = fgetc(Fi);
  707.     }
  708.     }
  709.  
  710.     if (c != ')')
  711.     error(FATAL, "Bad variable replacement spec: %c", c);
  712.  
  713.     CopyCmdListConvert(&var->var_CmdList, cmdList, AltBuf, SymBuf);
  714. }
  715.  
  716. #endif
  717.  
  718.  
  719. /*
  720.  *  GetToken()    - return a single token
  721.  */
  722.  
  723. #ifdef NOTDEF
  724. token_t
  725. GetToken()
  726. {
  727.     token_t t;
  728.     printf("get ");
  729.     fflush(stdout);
  730.     t = XGetToken();
  731.     printf("token %d\n", t);
  732.     return(t);
  733. }
  734. #endif
  735.  
  736. token_t
  737. GetToken()
  738. {
  739.     short c;
  740.     short i;
  741.  
  742.     for (;;) {
  743.     switch(c = getc(Fi)) {
  744.     case EOF:
  745.         return(0);
  746.     case ':':
  747.         return(TokColon);
  748.     case '=':
  749.         return(TokEq);
  750.     case '\n':
  751.         ++LineNo;
  752.         return(TokNewLine);
  753.     case '(':
  754.         return(TokOpenParen);
  755.     case ')':
  756.         return(TokCloseParen);
  757.     case '$':
  758.         return(TokDollar);
  759.     case '%':
  760.         return(TokPercent);
  761.     case ' ':
  762.     case '\t':
  763.     case '\014':
  764.     case '\r':
  765.         break;
  766.     case '#':
  767.         while ((c = getc(Fi)) != EOF) {
  768.         if (c == '\n') {
  769.             ++LineNo;
  770.             break;
  771.         }
  772.         }
  773.         break;
  774.     case '\"':
  775.         for (i = 0; i < sizeof(SymBuf) - 1 && (c = fgetc(Fi)) != EOF; ++i) {
  776.         if (c == '\n')
  777.             error(FATAL, "newline in control string");
  778.         if (c == '\"')
  779.             break;
  780.         if (c == '\\')
  781.             c = fgetc(Fi);
  782.         SymBuf[i] = c;
  783.         }
  784.         SymBuf[i] = 0;
  785.         if (i == sizeof(SymBuf) - 1)
  786.         error(FATAL, "Symbol overflow: %s", SymBuf);
  787.         if (c != '\"')
  788.         error(FATAL, "Expected closing quote");
  789.         return(TokStr);
  790.     case '\\':
  791.         c = fgetc(Fi);
  792.         if (c == '\n') {
  793.         ++LineNo;
  794.         break;
  795.         }
  796.         /* fall through */
  797.     default:
  798.         SymBuf[0] = c;
  799.  
  800.         for (i = 1; i < sizeof(SymBuf) - 1 && (c = getc(Fi)) != EOF; ++i) {
  801.         if (SpecialChar[c]) {
  802.             ungetc(c, Fi);
  803.             break;
  804.         }
  805.         SymBuf[i] = c;
  806.         }
  807.         SymBuf[i] = 0;
  808.         if (i == sizeof(SymBuf) - 1)
  809.         error(FATAL, "Symbol overflow: %s", SymBuf);
  810.         return(TokSym);
  811.     }
  812.     }
  813. }
  814.  
  815. void
  816. expect(token_t tgot, token_t twant)
  817. {
  818.     if (tgot != twant)
  819.     error(FATAL, "Unexpected token");
  820. }
  821.  
  822. void
  823. error(short type, const char *ctl, ...)
  824. {
  825.     static char *TypeString[] = { "Fatal", "Warning", "Debug" };
  826.     static char ExitAry[] = { 1, 0, 0 };
  827.     va_list va;
  828.  
  829.     printf("%s: %s Line %d: ", FileName, TypeString[type], LineNo);
  830.     va_start(va, ctl);
  831.     vprintf(ctl, va);
  832.     va_end(va);
  833.     puts("");
  834.     if (ExitAry[type])
  835.     exit(20);
  836. }
  837.  
  838.